﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Shapes;
using Drawer.Common;
using System.Windows.Threading;
using System.IO;
using System.Xml;

namespace Drawer.Controls
{
    /// <summary>
    /// Interaction logic for DrawCanvas.xaml
    /// </summary>
    public partial class DrawCanvas : UserControl
    {
        #region Declaration

        #region Events

        // Delegate declaration 
        public delegate void VisualChildrenChangeHandler(object sender, CanvasChildrenChangeEventArgs e);
        // Event declaration
        public event VisualChildrenChangeHandler VisualChildrenChanged;

        // Delegate declaration 
        public delegate void VisualChildEditHandler(object sender, CanvasChildEditEventArgs e);
        // Event declaration
        public event VisualChildEditHandler VisualChildEdited;

        #endregion Events

        #region Variables

        private Point startPoint;
        private bool isPreviewDrawing;

        private int editIndex;
        private ResizeDirections resizeDirection;

        private BaseShape editShape;
        private List<BaseShape> shapesList;
        private ActiveActions activeAction;
        private ActiveActions ActiveAction
        {
            get
            {
                return activeAction;
            }
            set
            {
                // Remove select outline first
                ClearSelectOutline();
                // Set new value for activeAction
                activeAction = value;
                // Set mouse cursor if activeAction is Draw
                if (activeAction == ActiveActions.Draw)
                {
                    drawCanvas.Cursor = Cursors.Cross;
                }
                // Set editShape = null if activeAction is Select
                if (activeAction == ActiveActions.Select)
                {
                    editShape = null;
                }
                // Clear variables use for Edit action
                if (activeAction != ActiveActions.Edit)
                {
                    resizeDirection = ResizeDirections.NotSet;
                }
            }
        }
        private List<int> Children_ShapeListMapper;

        #endregion Variables

        #region Properties

        public Brush Stroke { get; set; }
        public Brush Fill { get; set; }
        public int StrokeSize { get; set; }

        #endregion Properties

        #endregion Declaration

        public DrawCanvas()
        {
            InitializeComponent();

            drawCanvas.MouseLeftButtonDown += DrawCanvas_MouseLeftButtonDown;
            drawCanvas.MouseLeftButtonUp += DrawCanvas_MouseLeftButtonUp;
            drawCanvas.MouseMove += DrawCanvas_MouseMove;
            drawCanvas.KeyDown += DrawCanvas_KeyDown;

            isPreviewDrawing = false;

            ActiveAction = ActiveActions.Select;
            shapesList = new List<BaseShape>();
            //map between my own BaseShape in shapesList to my own Shape in drawCanvas.Children
            Children_ShapeListMapper = new List<int>();

            StrokeSize = 2;
        }

        #region Key Events Handler

        private void DrawCanvas_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
            if (activeAction == ActiveActions.Edit)
            {
                if (e.Key == Key.Delete)
                {
                    RemoveShapeAt(editIndex);

                    ActiveAction = ActiveActions.Select;
                }
            }
        }

        #endregion Key Events Handler

        #region Mouse Events Handler

        private void DrawCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            // Focus to Canvas
            (sender as Canvas).Focus();
            // Get StartPoint
            startPoint = e.GetPosition(sender as Canvas);

            if (ActiveAction == ActiveActions.Draw)
            {
                // Create editShape
                editShape = (BaseShape)Activator.CreateInstance(editShape.GetType());
                editShape.OutlineColor = Stroke;
                editShape.FillColor = Fill;
                editShape.StrokeSize = StrokeSize;
                // Set flag
                isPreviewDrawing = true;
            }
            else
            {
                // If users click to a shape
                for (int i = 0; i < drawCanvas.Children.Count; i++)
                {
                    if (drawCanvas.Children[i].IsMouseDirectlyOver && 
                        ((SolidColorBrush)((Shape)drawCanvas.Children[i]).Fill).Color.Equals(((SolidColorBrush)this.Fill).Color))
                    {
                        // Set ActiveAction to Move
                        ActiveAction = ActiveActions.Move;
                        // Set editIndex
                        //&&& editIndex = i;
                        editIndex = Children_ShapeListMapper[i];
                        //editIndex = i;
                        
                        // Create editShape
                        //&&& editShape = (BaseShape)Activator.CreateInstance(shapesList[i].GetType());                        
                        //&&& editShape.OutlineColor = shapesList[i].OutlineColor;
                        //&&& editShape.FillColor = shapesList[i].FillColor;
                        //&&& editShape.StrokeSize = shapesList[i].StrokeSize;

                        editShape = (BaseShape)Activator.CreateInstance(shapesList[Children_ShapeListMapper[i]].GetType());
                        editShape.OutlineColor = shapesList[Children_ShapeListMapper[i]].OutlineColor;
                        editShape.FillColor = shapesList[Children_ShapeListMapper[i]].FillColor;
                        editShape.StrokeSize = shapesList[Children_ShapeListMapper[i]].StrokeSize;

                        // Set selected shape become editShape
                        SetEditingShape(i);
                        // Set flag
                        isPreviewDrawing = true;
                        return;
                    }
                }
                // If users click to white space
                ActiveAction = ActiveActions.Select;
            }
        }

        private void DrawCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (isPreviewDrawing)
            {
                // Set preview flag to false
                isPreviewDrawing = false;
                // Clear current EditShape
                UnsetEditingShape();

                switch (ActiveAction)
                {
                    case ActiveActions.Draw:
                        {
                            break;
                        }
                    case ActiveActions.Move:
                        {
                            shapesList[editIndex] = editShape;
                            ActiveAction = ActiveActions.Edit;
                            DrawSelectOutline(shapesList[editIndex]);
                            break;
                        }
                    case ActiveActions.Edit:
                        {
                            shapesList[editIndex] = editShape;
                            ClearSelectOutline();
                            DrawSelectOutline(shapesList[editIndex]);
                            break;
                        }
                    default:
                        break;
                }
            }
        }

        private void DrawCanvas_MouseMove(object sender, MouseEventArgs e)
        {
            switch (ActiveAction)
            {
                case ActiveActions.Draw:
                    {
                        MouseMove_DrawHandler(sender, e);
                        break;
                    }
                case ActiveActions.Move:
                    {
                        MouseMove_DrawHandler(sender, e);
                        break;
                    }
                case ActiveActions.Edit:
                    {
                        MouseMove_DrawHandler(sender, e);
                        MouseMove_SelectHandler(sender, e);
                        break;
                    }
                case ActiveActions.Select:
                    {
                        MouseMove_SelectHandler(sender, e);
                        break;
                    }
                default:
                    break;
            }
        }

        private void MouseMove_DrawHandler(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed && isPreviewDrawing)
            {
                Point currentPoint = e.GetPosition(sender as Canvas);
                Point drawStartPoint = new Point();
                Point drawEndPoint = new Point();

                switch (ActiveAction)
                {
                    case ActiveActions.Draw:
                        {
                            drawStartPoint = new Point(startPoint.X, startPoint.Y);
                            drawEndPoint = new Point(currentPoint.X, currentPoint.Y);
                            break;
                        }
                    case ActiveActions.Edit:
                        {
                            drawStartPoint = new Point(startPoint.X, startPoint.Y);
                            switch (resizeDirection)
                            {
                                case ResizeDirections.N:
                                    {
                                        drawEndPoint = new Point(startPoint.X + shapesList[editIndex].Dimension.Width, currentPoint.Y);
                                        break;
                                    }
                                case ResizeDirections.E:
                                    {
                                        drawEndPoint = new Point(currentPoint.X, startPoint.Y - shapesList[editIndex].Dimension.Height);
                                        break;
                                    }
                                case ResizeDirections.S:
                                    {
                                        drawEndPoint = new Point(startPoint.X - shapesList[editIndex].Dimension.Width, currentPoint.Y);
                                        break;
                                    }
                                case ResizeDirections.W:
                                    {
                                        drawEndPoint = new Point(currentPoint.X, startPoint.Y + shapesList[editIndex].Dimension.Height);
                                        break;
                                    }
                                default:
                                    {
                                        drawEndPoint = new Point(currentPoint.X, currentPoint.Y);
                                        break;
                                    }
                            }
                            break;
                        }
                    case ActiveActions.Move:
                        {
                            drawStartPoint = new Point(shapesList[editIndex].StartPoint.X + currentPoint.X - startPoint.X,
                                shapesList[editIndex].StartPoint.Y + currentPoint.Y - startPoint.Y);
                            drawEndPoint = new Point(drawStartPoint.X + shapesList[editIndex].Dimension.Width,
                                drawStartPoint.Y + shapesList[editIndex].Dimension.Height);
                            break;
                        }
                    default:
                        break;
                }

                if (!drawStartPoint.Equals(new Point()) && !drawEndPoint.Equals(new Point()))
                {
                    double x = Math.Min(drawStartPoint.X, drawEndPoint.X);
                    double y = Math.Min(drawStartPoint.Y, drawEndPoint.Y);
                    double w = Math.Abs(drawStartPoint.X - drawEndPoint.X);
                    double h = Math.Abs(drawStartPoint.Y - drawEndPoint.Y);

                    if (w < StrokeSize * 2)
                    {
                        w = StrokeSize * 2;
                    }
                    if (h < StrokeSize * 2)
                    {
                        h = StrokeSize * 2;
                    }

                    editShape.StartPoint = new Point(x, y);
                    editShape.Dimension = new Dimension(w, h);

                    // add to canvas by user drawing
                    if (activeAction == ActiveActions.Draw)
                    {
                        if (!IsEditingShape())
                        {
                            AddShape(editShape);
                            SetEditingShape(drawCanvas.Children.Count - 1);
                            // map shapeList index to Children index
                            Children_ShapeListMapper.Add(shapesList.Count - 1);
                        }
                    }

                    UpdateEditingShape(editShape);
                }
            }
        }

        private void MouseMove_SelectHandler(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Released)
            {
                drawCanvas.Cursor = Cursors.Arrow;
                for (int i = 0; i < drawCanvas.Children.Count; i++)
                {
                    if (drawCanvas.Children[i].IsMouseDirectlyOver)
                    {
                        drawCanvas.Cursor = Cursors.Pen;
                        return;
                    }
                }
            }
        }

        #endregion Mouse Events Handler

        #region EditShape

        private void ResizeNode_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;

            Shape shape = sender as Shape;
            if (shape != null)
            {
                if (Enum.Parse(typeof(ResizeDirections), shape.Uid, true) != null)
                {
                    // Set resizeDirection
                    resizeDirection = (ResizeDirections)Enum.Parse(typeof(ResizeDirections), shape.Uid, true);
                    switch (resizeDirection)
                    {
                        case ResizeDirections.NW:
                            {
                                startPoint = new Point(shapesList[editIndex].StartPoint.X + shapesList[editIndex].Dimension.Width,
                                    shapesList[editIndex].StartPoint.Y + shapesList[editIndex].Dimension.Height);
                                break;
                            }
                        case ResizeDirections.SE:
                            {
                                startPoint = new Point(shapesList[editIndex].StartPoint.X,
                                    shapesList[editIndex].StartPoint.Y);
                                break;
                            }
                        case ResizeDirections.NE:
                            {
                                startPoint = new Point(shapesList[editIndex].StartPoint.X,
                                    shapesList[editIndex].StartPoint.Y + shapesList[editIndex].Dimension.Height);
                                break;
                            }
                        case ResizeDirections.SW:
                            {
                                startPoint = new Point(shapesList[editIndex].StartPoint.X + shapesList[editIndex].Dimension.Width,
                                    shapesList[editIndex].StartPoint.Y);
                                break;
                            }
                        case ResizeDirections.N:
                        case ResizeDirections.E:
                            {
                                startPoint = new Point(shapesList[editIndex].StartPoint.X,
                                    shapesList[editIndex].StartPoint.Y + shapesList[editIndex].Dimension.Height);
                                break;
                            }
                        case ResizeDirections.S:
                        case ResizeDirections.W:
                            {
                                startPoint = new Point(shapesList[editIndex].StartPoint.X + shapesList[editIndex].Dimension.Width,
                                    shapesList[editIndex].StartPoint.Y);
                                break;
                            }
                        default:
                            break;
                    }
                    // Clear select outline
                    ClearSelectOutline();
                    // Set selected shape become editShape
                    (drawCanvas.Children[editIndex] as Shape).Uid = Constants.SHAPE_IS_EDIT;
                    (drawCanvas.Children[editIndex] as Shape).IsHitTestVisible = false;
                    // Set flag
                    isPreviewDrawing = true;
                }
            }
        }

        private void ResizeNode_MouseEnter(object sender, MouseEventArgs e)
        {
            if (activeAction != ActiveActions.Edit)
                return;

            Shape shape = sender as Shape;
            if (shape != null)
            {
                if (Enum.Parse(typeof(ResizeDirections), shape.Uid, true) != null)
                {
                    ResizeDirections rDirection = (ResizeDirections)Enum.Parse(typeof(ResizeDirections), shape.Uid, true);
                    switch (rDirection)
                    {
                        case ResizeDirections.NW:
                        case ResizeDirections.SE:
                            {
                                shape.Cursor = Cursors.SizeNWSE;
                                break;
                            }
                        case ResizeDirections.NE:
                        case ResizeDirections.SW:
                            {
                                shape.Cursor = Cursors.SizeNESW;
                                break;
                            }
                        case ResizeDirections.N:
                        case ResizeDirections.S:
                            {
                                shape.Cursor = Cursors.SizeNS;
                                break;
                            }
                        case ResizeDirections.W:
                        case ResizeDirections.E:
                            {
                                shape.Cursor = Cursors.SizeWE;
                                break;
                            }
                        default:
                            break;
                    }
                }
            }
        }

        #endregion EditShape

        #region Settings Change Handlers

        public void Toolbar_SelectedShapeChanged(BaseShape obj)
        {
            ActiveAction = obj != null ? ActiveActions.Draw : ActiveActions.Select;
            if (obj != null)
                editShape = obj;
        }

        #endregion Settings Change Handlers

        #region Helper Methods

        private void DrawSelectOutline(BaseShape shape)
        {
            Dimension dimension = shape.Dimension;
            Point startPoint = shape.StartPoint;

            Rectangle outlineRect = new Rectangle
            {
                Width = dimension.Width,
                Height = dimension.Height,
                Margin = new Thickness(startPoint.X, startPoint.Y, 0, 0),
                Stroke = Brushes.Black,
                StrokeThickness = 1,
                IsHitTestVisible = false,
                Uid = Constants.EDIT_BOUNDARY
            };
            drawCanvas.Children.Add(outlineRect);

            Ellipse cornerEllipse = new Ellipse
            {
                Width = Constants.RESIZE_CIRCLE_SIZE,
                Height = Constants.RESIZE_CIRCLE_SIZE,
                Stroke = Brushes.Black,
                Fill = Brushes.WhiteSmoke,
                StrokeThickness = 1,
            };

            cornerEllipse = (Ellipse)Utils.CopyUIElement((UIElement)cornerEllipse);
            cornerEllipse.Uid = ResizeDirections.NW.ToString();
            cornerEllipse.Margin = new Thickness(startPoint.X - Constants.RESIZE_CIRCLE_SIZE / 2,
                startPoint.Y - Constants.RESIZE_CIRCLE_SIZE / 2, 0, 0);
            cornerEllipse.MouseEnter += ResizeNode_MouseEnter;
            cornerEllipse.MouseLeftButtonDown += ResizeNode_MouseLeftButtonDown;
            drawCanvas.Children.Add(cornerEllipse);

            cornerEllipse = (Ellipse)Utils.CopyUIElement((UIElement)cornerEllipse);
            cornerEllipse.Uid = ResizeDirections.NE.ToString();
            cornerEllipse.Margin = new Thickness(startPoint.X + dimension.Width - Constants.RESIZE_CIRCLE_SIZE / 2,
                startPoint.Y - Constants.RESIZE_CIRCLE_SIZE / 2, 0, 0);
            cornerEllipse.MouseEnter += ResizeNode_MouseEnter;
            cornerEllipse.MouseLeftButtonDown += ResizeNode_MouseLeftButtonDown;
            drawCanvas.Children.Add(cornerEllipse);

            cornerEllipse = (Ellipse)Utils.CopyUIElement((UIElement)cornerEllipse);
            cornerEllipse.Uid = ResizeDirections.SE.ToString();
            cornerEllipse.Margin = new Thickness(startPoint.X + dimension.Width - Constants.RESIZE_CIRCLE_SIZE / 2,
                startPoint.Y + dimension.Height - Constants.RESIZE_CIRCLE_SIZE / 2, 0, 0);
            cornerEllipse.MouseEnter += ResizeNode_MouseEnter;
            cornerEllipse.MouseLeftButtonDown += ResizeNode_MouseLeftButtonDown;
            drawCanvas.Children.Add(cornerEllipse);

            cornerEllipse = (Ellipse)Utils.CopyUIElement((UIElement)cornerEllipse);
            cornerEllipse.Uid = ResizeDirections.SW.ToString();
            cornerEllipse.Margin = new Thickness(startPoint.X - Constants.RESIZE_CIRCLE_SIZE / 2,
                startPoint.Y + dimension.Height - Constants.RESIZE_CIRCLE_SIZE / 2, 0, 0);
            cornerEllipse.MouseEnter += ResizeNode_MouseEnter;
            cornerEllipse.MouseLeftButtonDown += ResizeNode_MouseLeftButtonDown;
            drawCanvas.Children.Add(cornerEllipse);

            Rectangle sideRectangle = new Rectangle
            {
                Width = Constants.RESIZE_RECT_SIZE,
                Height = Constants.RESIZE_RECT_SIZE,
                Stroke = Brushes.Black,
                Fill = Brushes.WhiteSmoke,
                StrokeThickness = 1
            };

            if (shape.Dimension.Width > Constants.RESIZE_RECT_SIZE + Constants.RESIZE_CIRCLE_SIZE)
            {
                sideRectangle = (Rectangle)Utils.CopyUIElement((UIElement)sideRectangle);
                sideRectangle.Uid = ResizeDirections.N.ToString();
                sideRectangle.Margin = new Thickness(startPoint.X + dimension.Width / 2 - Constants.RESIZE_RECT_SIZE / 2,
                    startPoint.Y - Constants.RESIZE_RECT_SIZE / 2, 0, 0);
                sideRectangle.MouseEnter += ResizeNode_MouseEnter;
                sideRectangle.MouseLeftButtonDown += ResizeNode_MouseLeftButtonDown;
                drawCanvas.Children.Add(sideRectangle);

                sideRectangle = (Rectangle)Utils.CopyUIElement((UIElement)sideRectangle);
                sideRectangle.Uid = ResizeDirections.S.ToString();
                sideRectangle.Margin = new Thickness(startPoint.X + dimension.Width / 2 - Constants.RESIZE_RECT_SIZE / 2,
                    startPoint.Y + dimension.Height - Constants.RESIZE_RECT_SIZE / 2, 0, 0);
                sideRectangle.MouseEnter += ResizeNode_MouseEnter;
                sideRectangle.MouseLeftButtonDown += ResizeNode_MouseLeftButtonDown;
                drawCanvas.Children.Add(sideRectangle);
            }

            if (shape.Dimension.Height > Constants.RESIZE_RECT_SIZE + Constants.RESIZE_CIRCLE_SIZE)
            {
                sideRectangle = (Rectangle)Utils.CopyUIElement((UIElement)sideRectangle);
                sideRectangle.Uid = ResizeDirections.W.ToString();
                sideRectangle.Margin = new Thickness(startPoint.X - Constants.RESIZE_RECT_SIZE / 2,
                    startPoint.Y + dimension.Height / 2 - Constants.RESIZE_RECT_SIZE / 2, 0, 0);
                sideRectangle.MouseEnter += ResizeNode_MouseEnter;
                sideRectangle.MouseLeftButtonDown += ResizeNode_MouseLeftButtonDown;
                drawCanvas.Children.Add(sideRectangle);

                sideRectangle = (Rectangle)Utils.CopyUIElement((UIElement)sideRectangle);
                sideRectangle.Uid = ResizeDirections.E.ToString();
                sideRectangle.Margin = new Thickness(startPoint.X + dimension.Width - Constants.RESIZE_RECT_SIZE / 2,
                    startPoint.Y + dimension.Height / 2 - Constants.RESIZE_RECT_SIZE / 2, 0, 0);
                sideRectangle.MouseEnter += ResizeNode_MouseEnter;
                sideRectangle.MouseLeftButtonDown += ResizeNode_MouseLeftButtonDown;
                drawCanvas.Children.Add(sideRectangle);
            }
        }

        private void ClearSelectOutline()
        {
            for (int i = 0; i < drawCanvas.Children.Count; i++)
            {
                if ((drawCanvas.Children[i] as Shape).Uid == Constants.EDIT_BOUNDARY)
                {
                    drawCanvas.Children.RemoveRange(i, drawCanvas.Children.Count - i);
                    break;
                }
            }
        }

        private void AddShape(BaseShape newShape)
        {
            shapesList.Add(newShape);
            drawCanvas.Children.Add(newShape.GetShape());

            if (VisualChildrenChanged != null)
            {
                string visualAddedString = XamlWriter.Save(newShape.GetShape());
                string visualRemovedString = string.Empty;
                int changedIndex = drawCanvas.Children.Count - 1;

                VisualChildrenChanged(this, new CanvasChildrenChangeEventArgs(visualAddedString, visualRemovedString, changedIndex));
            }
        }

        private void RemoveShapeAt(int index)
        {
            Shape removedShape = drawCanvas.Children[index] as Shape;
            //&&& shapesList.RemoveAt(index);
            shapesList.RemoveAt(Children_ShapeListMapper[index]);
            drawCanvas.Children.RemoveAt(index);

            if (VisualChildrenChanged != null)
            {
                string visualAddedString = string.Empty;
                string visualRemovedString = XamlWriter.Save(removedShape);
                int changedIndex = index;

                VisualChildrenChanged(this, new CanvasChildrenChangeEventArgs(visualAddedString, visualRemovedString, changedIndex));
            }
        }

        private void UpdateEditingShape(BaseShape newShape)
        {
            if (newShape == null)
                return;
            for (int i = 0; i < drawCanvas.Children.Count; i++)
            {
                if ((drawCanvas.Children[i] as Shape).Uid == Constants.SHAPE_IS_EDIT)
                {
                    drawCanvas.Children.RemoveAt(i);
                    drawCanvas.Children.Insert(i, newShape.GetShape());
                    (drawCanvas.Children[i] as Shape).Uid = Constants.SHAPE_IS_EDIT;
                    (drawCanvas.Children[i] as Shape).IsHitTestVisible = false;

                    if (VisualChildEdited != null)
                    {
                        string updateChild = XamlWriter.Save(newShape.GetShape());
                        int index = i;

                        VisualChildEdited(this, new CanvasChildEditEventArgs(updateChild, index));
                    }
                    break;
                }
            }
        }

        private bool IsEditingShape()
        {
            for (int i = 0; i < drawCanvas.Children.Count; i++)
            {
                if ((drawCanvas.Children[i] as Shape).Uid == Constants.SHAPE_IS_EDIT)
                {
                    return true;
                }
            }
            return false;
        }

        private void UnsetEditingShape()
        {
            for (int i = 0; i < drawCanvas.Children.Count; i++)
            {
                if ((drawCanvas.Children[i] as Shape).Uid == Constants.SHAPE_IS_EDIT)
                {
                    (drawCanvas.Children[i] as Shape).Uid = string.Empty;
                    (drawCanvas.Children[i] as Shape).IsHitTestVisible = true;
                    break;
                }
            }
        }

        private void SetEditingShape(int index)
        {
            (drawCanvas.Children[index] as Shape).Uid = Constants.SHAPE_IS_EDIT;
            (drawCanvas.Children[index] as Shape).IsHitTestVisible = false;
        }

        #endregion Helper Methods

        #region Canvas edit
        public delegate void DrawDelegate();
        String visualAdded;
        int changedIndex;
        public void AddChild(string user, string childAdded, int index)
        {
            if (!string.IsNullOrEmpty(childAdded) && index >= 0)
            {
                this.visualAdded = childAdded;
                this.changedIndex = index;
                this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                    new DrawDelegate(AddToCanvas));

            }
        }

        public void RemoveChild(string user, string childRemoved, int index)
        {
            if (!string.IsNullOrEmpty(childRemoved) && index >= 0)
            {
                this.changedIndex = index;
                this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                    new DrawDelegate(RemoveFromCanvas));
            }
        }

        public void UpdateChild(string user, string childUpdated, int index)
        {
            if (!string.IsNullOrEmpty(childUpdated) && index >= 0)
            {
                this.visualAdded = childUpdated;
                this.changedIndex = index;
                this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                    new DrawDelegate(UpdateToCanvas));
            }
        }

        private void AddToCanvas()
        {
            if (!string.IsNullOrEmpty(visualAdded))
            {
                using (StringReader stringReader = new StringReader(visualAdded))
                {
                    XmlTextReader xmlTextReader = new XmlTextReader(stringReader);
                    drawCanvas.Children.Insert(changedIndex, XamlReader.Load(xmlTextReader) as UIElement);
                    //Shape bs = (Shape)(XamlReader.Load(xmlTextReader) as UIElement);
                    //shapesList.Add(bs);
                    System.Console.WriteLine("AddToCanvas");
                    // mean that there is no BaseShape in shapesList corresponding to this new element
                    Children_ShapeListMapper.Add(-1);
                }
            }
        }

        private void UpdateToCanvas()
        {
            try
            {
                if (!string.IsNullOrEmpty(visualAdded))
                {
                    using (StringReader stringReader = new StringReader(visualAdded))
                    {
                        if (changedIndex < drawCanvas.Children.Count)
                        {
                            XmlTextReader xmlTextReader = new XmlTextReader(stringReader);
                            drawCanvas.Children.RemoveAt(changedIndex);
                            drawCanvas.Children.Insert(changedIndex, XamlReader.Load(xmlTextReader) as UIElement);
                            System.Console.WriteLine("UpdateToCanvas");
                        }
                        else
                        {
                            //MessageBox.Show("UpdateToCanvas out: " + drawCanvas.Children.Count + " " + changedIndex);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                System.Console.WriteLine(e.StackTrace);
                MessageBox.Show(drawCanvas.Children.Count + " " + changedIndex);
            }
        }

        public void RemoveFromCanvas()
        {
            drawCanvas.Children.RemoveAt(changedIndex);
            shapesList.RemoveAt(Children_ShapeListMapper[changedIndex]);
        }

        private DependencyObject XamlToUIElement(string content)
        {
            using (StringReader stringReader = new StringReader(content))
            {
                XmlTextReader xmlTextReader = new XmlTextReader(stringReader);
                return XamlReader.Load(xmlTextReader) as DependencyObject;
            }
        } 
        #endregion


    }
}